package com.todo.pro.controller;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.todo.pro.admin.service.AdminSystemUserService;
import com.todo.pro.captcha.CaptchaUtil;
import com.todo.pro.entity.SystemUser;
import com.todo.pro.handle.EE;
import com.todo.pro.jwt.JwtUtil;
import com.todo.pro.res.JsonResult;
import com.todo.pro.res.model.UserInfoResult;
import com.todo.pro.res.table.UserResult;
import com.todo.pro.service.SystemUserService;
import com.todo.pro.shiro.SubjectUtil;
import com.todo.pro.util.MapUtil;
import com.todo.pro.util.RegexUtils;
import com.xiaoleilu.hutool.crypto.SecureUtil;
import com.xiaoleilu.hutool.date.DateUtil;
import com.xiaoleilu.hutool.util.NumberUtil;
import com.xiaoleilu.hutool.util.RandomUtil;

/**
 * @author SiZhongxia
 * @since 2017-12-27
 */
@Controller
@RequestMapping("user")
public class UserController extends BaseController {

	private Logger logger = LoggerFactory.getLogger(UserController.class);

	@Autowired
	private SystemUserService systemUserService;
	@Autowired
	private AdminSystemUserService adminSystemUserService;

	@ResponseBody
	@RequestMapping(value = "login")
	public JsonResult<Object> login(HttpServletRequest request) {

		String code = request.getParameter("code");
		if (StringUtils.isBlank(code)) {
			return new JsonResult<Object>(false, EE.NO_INPUT_VCODE.i());
		}

		if (!CaptchaUtil.ver(code)) {
			return new JsonResult<Object>(false, EE.VCODE_ERROR.i());
		}

		String username = request.getParameter("username");
		if (StringUtils.isBlank(username)) {
			return new JsonResult<Object>(false, EE.NO_INPUT_LOGINAME.i());
		}

		String password = request.getParameter("password");
		if (StringUtils.isBlank(password)) {
			return new JsonResult<Object>(false, EE.NO_INPUT_LOGINPSW.i());
		}

		UsernamePasswordToken token = new UsernamePasswordToken(username, SecureUtil.md5(password));
		// 默认禁止使用RememberMe
		token.setRememberMe(false);

		Subject subject = SecurityUtils.getSubject();
		String msg = "";
		try {
			subject.login(token);
		} catch (IncorrectCredentialsException e) {
			msg = EE.ERROR_LOGIN_PSW.i();
		} catch (LockedAccountException e) {
			msg = EE.ACCOUNT_LOCKED.i();
		} catch (DisabledAccountException e) {
			msg = EE.ACCOUNT_DISABLED.i();
		} catch (UnknownAccountException e) {
			msg = EE.UNKNOWN_ACCOUNT.i();
		} catch (UnauthorizedException e) {
			msg = EE.NO_AUTHORIZED.i();
		} catch (Exception e) {
			msg = EE.ERR_FOR_WAIT.i();
		}
		if (subject.isAuthenticated()) {
			return new JsonResult<Object>(true, EE.SUCCESS_LOGIN.i());
		}

		return new JsonResult<Object>(false, msg);
	}

	@ResponseBody
	@RequiresAuthentication
	@RequestMapping(value = "info")
	public JsonResult<UserInfoResult> info(HttpServletRequest request) {
		UserInfoResult ui = new UserInfoResult();
		SystemUser systemUser = SubjectUtil.getPrincipal();
		ui.setUserName(systemUser.getLoginName());
		return new JsonResult<UserInfoResult>(ui);
	}

	@RequiresAuthentication
	@RequestMapping(value = "resetpswpage")
	public ModelAndView resetpswpage(HttpServletRequest request) {
		ModelAndView mav = new ModelAndView("modules/user/resetpsw");
		mav.addObject("csrftoken",
				JwtUtil.createToken(MapUtil.init().putVal("path", "gq-user-resetpsw"), 10L * 60 * 1000));
		return mav;
	}

	@RequiresAuthentication
	@RequestMapping(value = "personal")
	public ModelAndView personal(HttpServletRequest request) {
		ModelAndView mav = new ModelAndView("modules/user/personal");
		
		SystemUser systemUser = SubjectUtil.getPrincipal();
		mav.addObject("loginName", systemUser.getLoginName());
		if(StringUtils.isBlank(systemUser.getPhoneNo())) {
			mav.addObject("phoneNo", "-");
		} else {
			mav.addObject("phoneNo", systemUser.getPhoneNo());
		}
		if(StringUtils.isBlank(systemUser.getEmail())) {
			mav.addObject("email", "-");
		} else {
			mav.addObject("email", systemUser.getEmail());
		}
		return mav;
	}

	@ResponseBody
	@RequiresAuthentication
	@RequestMapping(value = "changepsw")
	public JsonResult<Object> changepsw(HttpServletRequest request) {
		String csrftoken = request.getParameter("csrftoken");
		if (StringUtils.isBlank(csrftoken)) {
			return new JsonResult<Object>(false, EE.ERROR_FORM.i());
		}
		Map<String, Object> jwtData = JwtUtil.parseJWT(csrftoken);
		if (jwtData == null) {
			return new JsonResult<Object>(false, EE.ERROR_FORM_OVERDUE.i());
		}

		if (!"gq-user-resetpsw".equals(jwtData.get("path"))) {
			return new JsonResult<Object>(false, EE.ERROR_FORM.i());
		}

		String oldPsw = request.getParameter("oldPsw");
		if (StringUtils.isBlank(oldPsw)) {
			return new JsonResult<Object>(false, EE.NO_INPUT_ORIGINAL_PSW.i());
		}
		String newPsw = request.getParameter("newPsw");
		if (StringUtils.isBlank(newPsw)) {
			return new JsonResult<Object>(false, EE.NO_INPUT_NEW_PSW.i());
		}
		String rePsw = request.getParameter("rePsw");
		if (StringUtils.isBlank(rePsw)) {
			return new JsonResult<Object>(false, EE.NO_INPUT_RENEW_PSW.i());
		}
		if (!newPsw.equals(rePsw)) {
			return new JsonResult<Object>(false, EE.NEW_PSW_MISMATCH.i());
		}
		SystemUser systemUser = SubjectUtil.getPrincipal();
		if (!SecureUtil.md5(oldPsw).equals(systemUser.getPassword())) {
			return new JsonResult<Object>(false, EE.ORIGINAL_PSW_MISMATCH.i());
		}

		systemUser.setPassword(SecureUtil.md5(newPsw));
		systemUser.setUpdatePwTime(DateUtil.date());
		if (!systemUserService.updateById(systemUser)) {
			return new JsonResult<Object>(false, EE.ERR_FOR_WAIT.i());
		}

		return new JsonResult<Object>(true, EE.SUCCESS_OP.i());
	}

	@RequiresAuthentication
	@RequestMapping(value = "list")
	public ModelAndView list(HttpServletRequest request) {
		ModelAndView mav = new ModelAndView("modules/user/list");
		mav.addObject("csrftoken",
				JwtUtil.createToken(MapUtil.init().putVal("path", "gq-user-list"), 2L * 60 * 60 * 1000));
		return mav;
	}

	@ResponseBody
	@RequiresAuthentication
	@RequestMapping(value = "data")
	public JsonResult<List<UserResult>> data(HttpServletRequest request) {

		String orderField = request.getParameter("orderField");
		String orderByField = "create_time";
		if (StringUtils.isNotBlank(orderField)) {
			switch (orderField) {
			case "userName":
				orderByField = "login_name";
				break;
			case "enabled":
				orderByField = "is_enabled";
				break;
			case "locked":
				orderByField = "is_locked";
				break;
			}
		}
		boolean isAsc = true;
		String orderType = request.getParameter("orderType");
		if (StringUtils.isNotBlank(orderType)) {
			isAsc = "asc".equalsIgnoreCase(orderType);
		}

		String page = request.getParameter("page");
		int current = 1;
		if (NumberUtil.isInteger(page)) {
			current = new Integer(page);
		}
		String limit = request.getParameter("limit");
		int size = 10;
		if (NumberUtil.isInteger(limit)) {
			size = new Integer(limit);
		}

		String loginName = request.getParameter("loginName");

		if (StringUtils.isBlank(loginName)) {
			loginName = null;
		}

		Page<UserResult> pageInfo = new Page<>(current, size, orderByField, isAsc);
		pageInfo.setSearchCount(true);

		adminSystemUserService.selectUserPage(pageInfo, loginName);

		return new JsonResult<List<UserResult>>(pageInfo.getTotal(), pageInfo.getRecords());
	}

	@ResponseBody
	@RequiresAuthentication
	@RequestMapping(value = "changelockedstatus")
	public JsonResult<Object> changelockedstatus(HttpServletRequest request) {
		String userId = request.getParameter("userId");
		if (StringUtils.isBlank(userId)) {
			return new JsonResult<Object>(false, EE.INVALID_PARAMETERS.i());
		}
		String locked = request.getParameter("locked");
		if (!NumberUtil.isInteger(locked)) {
			return new JsonResult<Object>(false, EE.INVALID_PARAMETERS.i());
		}

		SystemUser systemUser = systemUserService.selectById(userId);
		if (systemUser == null) {
			return new JsonResult<Object>(false, EE.INVALID_PARAMETERS.i());
		}
		systemUser.setIsLocked(new Integer(locked));
		systemUser.setUpdateTime(DateUtil.date());
		if (!systemUserService.updateById(systemUser)) {
			return new JsonResult<Object>(false, EE.ERR_FOR_WAIT.i());
		}

		return new JsonResult<Object>(true, EE.SUCCESS_OP.i());
	}

	@ResponseBody
	@RequiresAuthentication
	@RequestMapping(value = "changeenabledstatus")
	public JsonResult<Object> changeenabledstatus(HttpServletRequest request) {
		String userId = request.getParameter("userId");
		if (StringUtils.isBlank(userId)) {
			return new JsonResult<Object>(false, EE.INVALID_PARAMETERS.i());
		}
		String enabled = request.getParameter("enabled");
		if (!NumberUtil.isInteger(enabled)) {
			return new JsonResult<Object>(false, EE.INVALID_PARAMETERS.i());
		}

		SystemUser systemUser = systemUserService.selectById(userId);
		if (systemUser == null) {
			return new JsonResult<Object>(false, EE.INVALID_PARAMETERS.i());
		}
		systemUser.setIsEnabled(new Integer(enabled));
		systemUser.setUpdateTime(DateUtil.date());
		if (!systemUserService.updateById(systemUser)) {
			return new JsonResult<Object>(false, EE.ERR_FOR_WAIT.i());
		}

		return new JsonResult<Object>(true, EE.SUCCESS_OP.i());
	}

	@ResponseBody
	@RequiresAuthentication
	@RequestMapping(value = "resetpublicpsw")
	public JsonResult<Object> resetpublicpsw(HttpServletRequest request) {
		String userId = request.getParameter("userId");
		if (StringUtils.isBlank(userId)) {
			return new JsonResult<Object>(false, EE.INVALID_PARAMETERS.i());
		}
		SystemUser systemUser = systemUserService.selectById(userId);
		if (systemUser == null) {
			return new JsonResult<Object>(false, EE.INVALID_PARAMETERS.i());
		}
		String password = RandomUtil.randomNumbers(6);
		systemUser.setPassword(SecureUtil.md5(password));
		systemUser.setUpdatePwTime(DateUtil.date());
		if (!systemUserService.updateById(systemUser)) {
			return new JsonResult<Object>(false, EE.ERR_FOR_WAIT.i());
		}

		return new JsonResult<Object>(true, password);
	}

	@RequiresAuthentication
	@RequestMapping(value = "edit")
	public ModelAndView edit(HttpServletRequest request) {
		ModelAndView mav = new ModelAndView();

		String userId = request.getParameter("userId");
		if (StringUtils.isBlank(userId)) {
			mav.setViewName("error/serverbusy");
			return mav;
		}
		SystemUser systemUser = systemUserService.selectById(userId);
		if (systemUser == null) {
			mav.setViewName("error/serverbusy");
			return mav;
		}

		mav.setViewName("modules/user/edit");
		mav.addObject("userId", systemUser.getId().toString());
		mav.addObject("loginName", systemUser.getLoginName());
		mav.addObject("phoneNo", systemUser.getPhoneNo());
		mav.addObject("email", systemUser.getEmail());
		mav.addObject("csrftoken", JwtUtil.createToken(MapUtil.init().putVal("path", "gq-user-edit"), 30L * 60 * 1000));
		return mav;
	}

	@ResponseBody
	@RequiresAuthentication
	@RequestMapping(value = "update")
	public JsonResult<Object> update(HttpServletRequest request) {
		String csrftoken = request.getParameter("csrftoken");
		if (StringUtils.isBlank(csrftoken)) {
			return new JsonResult<Object>(false, EE.ERROR_FORM.i());
		}
		Map<String, Object> jwtData = JwtUtil.parseJWT(csrftoken);
		if (jwtData == null) {
			return new JsonResult<Object>(false, EE.ERROR_FORM_OVERDUE.i());
		}

		if (!"gq-user-edit".equals(jwtData.get("path"))) {
			return new JsonResult<Object>(false, EE.ERROR_FORM.i());
		}

		String userId = request.getParameter("userId");
		if (StringUtils.isBlank(userId)) {
			return new JsonResult<Object>(false, EE.INVALID_PARAMETERS.i());
		}

		String phoneNo = request.getParameter("phoneNo");
		if (StringUtils.isBlank(phoneNo)) {
			phoneNo = "";
		} else {
			if (!RegexUtils.checkPhone(phoneNo)) {
				return new JsonResult<Object>(false, EE.PHONE_NO_FORMAT_ERRPR.i());
			}
		}

		String email = request.getParameter("email");
		if (StringUtils.isBlank(email)) {
			email = "";
		} else {
			if (!RegexUtils.checkEmail(email)) {
				return new JsonResult<Object>(false, EE.EMAIL_FORMAT_ERRPR.i());
			}
		}

		SystemUser systemUser = systemUserService.selectById(userId);
		if (systemUser == null) {
			return new JsonResult<Object>(false, EE.INVALID_PARAMETERS.i());
		}

		systemUser.setPhoneNo(phoneNo);
		systemUser.setEmail(email);
		systemUser.setUpdateTime(DateUtil.date());
		if (!systemUserService.updateById(systemUser)) {
			return new JsonResult<Object>(false, EE.ERR_FOR_WAIT.i());
		}

		return new JsonResult<Object>(true, EE.SUCCESS_OP.i());
	}

	@RequiresAuthentication
	@RequestMapping(value = "add")
	public ModelAndView add(HttpServletRequest request) {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("modules/user/add");
		mav.addObject("csrftoken", JwtUtil.createToken(MapUtil.init().putVal("path", "gq-user-add"), 30L * 60 * 1000));
		return mav;
	}

	@ResponseBody
	@RequiresAuthentication
	@RequestMapping(value = "save")
	public JsonResult<Object> save(HttpServletRequest request) {
		String csrftoken = request.getParameter("csrftoken");
		if (StringUtils.isBlank(csrftoken)) {
			return new JsonResult<Object>(false, EE.ERROR_FORM.i());
		}
		Map<String, Object> jwtData = JwtUtil.parseJWT(csrftoken);
		if (jwtData == null) {
			return new JsonResult<Object>(false, EE.ERROR_FORM_OVERDUE.i());
		}

		if (!"gq-user-add".equals(jwtData.get("path"))) {
			return new JsonResult<Object>(false, EE.ERROR_FORM.i());
		}

		String loginName = request.getParameter("loginName");
		if (StringUtils.isBlank(loginName)) {
			return new JsonResult<Object>(false, EE.ERROR_FORM.i());
		}
		String password = request.getParameter("password");
		if (StringUtils.isBlank(password)) {
			return new JsonResult<Object>(false, EE.ERROR_FORM.i());
		}

		String phoneNo = request.getParameter("phoneNo");
		if (StringUtils.isBlank(phoneNo)) {
			phoneNo = "";
		} else {
			if (!RegexUtils.checkPhone(phoneNo)) {
				return new JsonResult<Object>(false, EE.PHONE_NO_FORMAT_ERRPR.i());
			}
		}

		String email = request.getParameter("email");
		if (StringUtils.isBlank(email)) {
			email = "";
		} else {
			if (!RegexUtils.checkEmail(email)) {
				return new JsonResult<Object>(false, EE.EMAIL_FORMAT_ERRPR.i());
			}
		}

		Wrapper<SystemUser> systemUserWrapper = new EntityWrapper<>();
		systemUserWrapper.eq("login_name", loginName);
		SystemUser systemUser = systemUserService.selectOne(systemUserWrapper);
		if (systemUser != null) {
			return new JsonResult<Object>(false, EE.LOGIN_NAME_EXSIT.i());
		}
		systemUser = new SystemUser();
		systemUser.setLoginName(loginName);
		systemUser.setPassword(SecureUtil.md5(password));
		systemUser.setPhoneNo(phoneNo);
		systemUser.setEmail(email);
		systemUser.setIsLocked(1);
		systemUser.setIsEnabled(0);
		systemUser.setCreateTime(DateUtil.date());
		systemUser.setUpdatePwTime(DateUtil.date());
		systemUser.setUpdateTime(DateUtil.date());
		if (!systemUserService.insert(systemUser)) {
			return new JsonResult<Object>(false, EE.ERR_FOR_WAIT.i());
		}

		return new JsonResult<Object>(true, EE.SUCCESS_OP.i());
	}

	@ResponseBody
	@RequiresAuthentication
	@RequestMapping(value = "delete")
	public JsonResult<Object> delete(HttpServletRequest request) {
		String csrftoken = request.getParameter("csrftoken");
		if (StringUtils.isBlank(csrftoken)) {
			return new JsonResult<Object>(false, EE.ERROR_FORM.i());
		}
		Map<String, Object> jwtData = JwtUtil.parseJWT(csrftoken);
		if (jwtData == null) {
			return new JsonResult<Object>(false, EE.ERROR_FORM_OVERDUE.i());
		}

		if (!"gq-user-list".equals(jwtData.get("path"))) {
			return new JsonResult<Object>(false, EE.ERROR_FORM.i());
		}

		String[] userIds = request.getParameterValues("userIds[]");
		if (userIds == null || userIds.length == 0) {
			return new JsonResult<Object>(false, EE.SELECT_LEAST_ONE_RECORD.i());
		}

		Set<Long> deleteUserIds = new HashSet<>();
		for (String userId : userIds) {
			deleteUserIds.add(new Long(userId));
		}

		if (!systemUserService.deleteBatchIds(deleteUserIds)) {
			return new JsonResult<Object>(false, EE.ERR_FOR_WAIT.i());
		}

		return new JsonResult<Object>(true, EE.SUCCESS_OP.i());
	}
}
